10299. Родственники
По заданному положительному
целому числу n вычислить количество чисел, меньших n и взаимно
простых с n.
Вход.
Каждая входная строка содержит число n (n £ 1.000.000.000). Число n = 0 является концом входных данных и не
обрабатывается.
Выход. Для каждого входного числа
вывести ответ на вопрос, поставленный в условии задачи.
7
12
0
Пример выхода
6
4
теория чисел – функция Эйлера
Сведенной системой вычетов Zn*
называется множество натуральных чисел, меньших n и взаимно простых с n.
Ответом на поставленный вопрос будет мощность (количество элементов) множества
Zn*. Известно, что |Zn*|
= j(n),
где j – функция
Эйлера. Если n = – разложение числа n
на простые множители, то
j(n) = n * (1 – 1/p1)
* (1 – 1/p2) * … * (1 – 1/pt)
При этом следует помнить, что для
n = 1 ответом будет 0 (не существует ни одного целого положительного
числа, меньшего 1).
Рассмотрим второй тест. Сведенная
система вычетов по модулю 12 имеет вид: Z12* = {1, 5, 7,
11}, ее мощность равна |Z12*| = 4. Этот же результат
можно получить, вычислив функцию Эйлера: j(12) = j(22 * 3) = 12 * (1 –
1/2) * (1 – 1/3) = 12 * (1/2) * (2/3) = 4.
В задаче достаточно использовать
для целочисленных переменных тип данных int, так как в языке С тип int
четырехбайтный (в который помещаются числа до 109). Читаем значение n.
Если оно равно 1, то выводим результат 0.
while (scanf("%d",&n)
== 1 && n)
{
if (n == 1)
{
printf("0\n"); continue;
}
В переменной result
накапливаем значение j(n). Изначально положим result = n. Делители числа n
ищем, перебирая все значения i
от 2 до . При нахождении делителя i умножаем result на
(1 - 1/i) (операция result = result * ( 1 - 1/i)
эквивалентна result = result - result / i) и делим
значение n на i до тех пор, пока деление производится без остатка
(функция Эйлера j(n)
зависит только от делителей числа n, а не степеней с которыми они входят
в разложение n на множители).
result = n;
for(i = 2; i <= sqrt(1.0*n); i++)
{
if (n % i == 0) result -= result / i;
while (n % i == 0) n /= i;
}
Если после выполнения цикла значение
n все еще больше 1, то исходное значение n содержало делитель,
больший . И текущее n как раз равно этому делителю. Учтем его
в формуле вычисления функции Эйлера. После чего выведем результат.
if (n > 1)
result -= result / n;
printf("%d\n",result);
}